package com.archermind.style.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.archermind.style.bean.*;
import com.archermind.style.pojo.*;
import com.archermind.style.util.*;
import com.feng.fengDUtil.BaseService;
import com.feng.fengDUtil.Page;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.dom.DOMElement;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Transactional
public class ReleaseService  extends BaseService {

    private static final Logger log = LoggerFactory.getLogger(ReleaseService.class);

    @Value("${releaseUrl}")
    public String releaseUrl;

    @Autowired
    private InstanceService instanceService;

    @Autowired
    private StyleTypeService styleTypeService;

    @Autowired
    private DictService dictService;

    @Autowired
    private OperationService opService;

    @Autowired
    private IconService iconService;

    //导入样式 图片路径
    public static ThreadLocal<Map<Integer,IconPojo>> iconPojoMapThreadLocal = new ThreadLocal<Map<Integer,IconPojo>>();

    public Page query(Page page, Search search) {
        ArrayList params = new ArrayList();
        String sql = "select u.*, " +
                "(select text From attachment_folder i where i.id = u.attachmentFolderId) as attachmentFolder, " +
                "(select group_concat(name) From instance i where find_in_set(i.id,u.instanceIds)) as instanceNames, " +
                "(select s.name From user s where s.id = u.creator limit 1) as creatorName, " +
                "(select s.name From user s where s.id = u.modifier limit 1) as modifierName" +
                " from release_log u where 1=1 ";
        if(StringUtils.isNotEmpty(search.getName())){
            sql+=" and name like ?";
            params.add(processLike(search.getName()));
        }
        if(search.getSceneId()!=null){
            sql+=" and sceneId = ?";
            params.add(search.getSceneId());
        }
        Integer userId =SessionUtil.getCurUserId();
        if(!new Integer(1).equals(userId)){
            sql+=" and u.creator = ?";
            params.add(userId);
        }
        sql+="  order by id desc";
        findPageList(Map.class,sql,page,params.toArray());
        return page;
    }

    public void delReleases(String ids) {
        List<Release> items = selectByIds(Release.class,Arrays.asList(ids.split(",")));
        for(Release item:items){
            deleteFileByPath(item.getZipPath());
            deleteFileByPath(item.getRespPath());
            opService.saveLog("删除了发布历史："+item.getName());
        }
        deleteById(Release.class,ids);
    }

    private void deleteFileByPath(String path){
        if(StringUtils.isNotEmpty(path)){
            File file = new File(Constants.webRoot.getAbsolutePath(),path);
            if(file.exists()){
                file.delete();
            }
        }
    }

    public static Document str2XML(String string) throws DocumentException {

        SAXReader reader = new SAXReader();

        Document document = reader.read(new StringReader(string));

        return document;

    }

    /**
     * 生成样式xml，用于发布或者下载
     * @param instance
     * @return
     * @throws DocumentException
     */
    public Document geneXml(Instance instance) throws DocumentException {
        String styleTmplUrl = Constants.webRoot.getAbsolutePath()+"/res/styleTmpl.xml";
        SAXReader saxReader = new SAXReader();
        Document doc = saxReader.read(styleTmplUrl);
        Element root = doc.getRootElement();
        System.out.println( "获取了根元素:"+root.getName()  );
        Element aliasStyleDefine =  root.element("AliasStyleDefine");
        Element commonStyleDefine =  root.element("CommonStyleDefine");

        if(StringUtils.isNotEmpty(instance.getBaseMapStyle())){
            Element baseMapStyle =  commonStyleDefine.element("BaseMapStyle");
            baseMapStyle.clearContent();
            JSONArray keyValues = JSON.parseArray(instance.getBaseMapStyle());
            StringBuffer bf = new StringBuffer();
            for(int i=0;i<keyValues.size();i++){
                String kv = keyValues.getString(i);
                Document temp = str2XML(new StringBuilder().append("<KVItem ").append(kv).append(" />").toString());
                baseMapStyle.add(temp.getRootElement());
            }
        }

        Element pointStyleDefine = root.element(ElementEnum.point.getStyleTag());
        Element lineStyleDefine = root.element(ElementEnum.line.getStyleTag());
        Element polygonStyleDefine = root.element(ElementEnum.polygon.getStyleTag());
        Element buildingStyleDefine = root.element(ElementEnum.building.getStyleTag());
        Element arrowStyleDefine = root.element(ElementEnum.arrow.getStyleTag());
        Element roadSignStyleDefine = root.element(ElementEnum.roadSign.getStyleTag());

        Element textStyleDefine = root.element(ElementEnum.text.getStyleTag());

        Element aliasTextDefine = aliasStyleDefine.element(ElementEnum.text.getTypeTag());

        Integer instanceId = instance.getId();
        Map<String,IconPojo> iconMap = getAllIcon(instance);
        styleTypeService.getStyleTypeMapByElements(ElementEnum.text.name(),ElementEnum.dashLine.name());

        List<RulePoint> points = sql("select * from rule_point where instanceId = ? and exists (select 1 from style_type t where t.id = styleTypeId) order by styleTypeId,cast(scale as DECIMAL) asc ").list(RulePoint.class,instanceId);
        List<RuleLine> lines = sql("select * from rule_line where instanceId = ? and exists (select 1 from style_type t where t.id = styleTypeId) order by styleTypeId,cast(scale as DECIMAL) asc ").list(RuleLine.class,instanceId);
        List<RulePolygon> polygons = sql("select * from rule_polygon where instanceId = ? and exists (select 1 from style_type t where t.id = styleTypeId) order by styleTypeId,cast(scale as DECIMAL) asc ").list(RulePolygon.class,instanceId);
        List<RuleBuilding> buildings = sql("select * from rule_building where instanceId = ? and exists (select 1 from style_type t where t.id = styleTypeId) order by styleTypeId,cast(scale as DECIMAL) asc ").list(RuleBuilding.class,instanceId);
        List<RuleArrow> arrows = sql("select * from rule_arrow where instanceId = ? and exists (select 1 from style_type t where t.id = styleTypeId) order by styleTypeId,cast(scale as DECIMAL) asc ").list(RuleArrow.class,instanceId);
        List<RuleRoadSign> roadSigns = sql("select * from rule_roadSign where instanceId = ? and exists (select 1 from style_type t where t.id = styleTypeId) order by styleTypeId,cast(scale as DECIMAL) asc ").list(RuleRoadSign.class,instanceId);

        List<DictColor> colors = sql("select * from dict_color where instanceId = ?").list(DictColor.class,instanceId);
        List<DictFont> fonts = sql("select * from dict_font where instanceId = ?").list(DictFont.class,instanceId);
        List<DictFontSize> fontSizes = sql("select * from dict_font_size where instanceId = ?").list(DictFontSize.class,instanceId);
        List<DictDashLine> dashLines = dictService.getDictDashLines(instanceId);


        instanceService.transKeyToObj(points, lines, polygons, buildings, arrows, roadSigns, colors, fonts, fontSizes, dashLines);
        List<RuleText> ruleTexts = new ArrayList<>();


        for(RulePoint rule : points){
            if(rule.getDictFontName()!=null){
                RuleText text = new RuleText();
                dictService.bcPoint.copy(rule,text,null);
                text.setTexttype(TextTypeEnum.PointTextSymbolizer);
                ruleTexts.add(text);
            }
        }

        for(RuleLine rule : lines){
            if(rule.getDictFontName()!=null){
                RuleText text = new RuleText();
                dictService.bcLine.copy(rule,text,null);
                text.setTexttype(TextTypeEnum.LineTextSymbolizer);
                ruleTexts.add(text);
            }
        }

        for(RuleRoadSign rule : roadSigns){
            if(rule.getDictFontName()!=null){
                RuleText text = new RuleText();
                dictService.bcRoadSign.copy(rule,text,null);
                text.setTexttype(TextTypeEnum.LableIconSymbolizer);
                ruleTexts.add(text);
            }
        }

        fillIconStyleDefine(aliasStyleDefine,commonStyleDefine, iconMap);
        fillDashLineStyleDefine(aliasStyleDefine,commonStyleDefine, dashLines);

        List<Element> notSortedList = new ArrayList();
        List<Integer> usedTextIds = new ArrayList();
        for(ElementEnum ele:ElementEnum.getRuleValues()){
            List<StyleType> styleTypeList = styleTypeService.listByElement(ele,instanceId,true);

            if(ele.equals(ElementEnum.point)||ele.equals(ElementEnum.line)||ele.equals(ElementEnum.roadSign)){
                Element firstRuleDom = null;
                StyleType tempStyle = null;
                Element textDom = null;
                for(RuleText text:ruleTexts){
                    if(ele.equals(ElementEnum.point) && !TextTypeEnum.PointTextSymbolizer.equals(text.getTexttype())){
                        continue;
                    }else if(ele.equals(ElementEnum.line) && !TextTypeEnum.LineTextSymbolizer.equals(text.getTexttype())){
                        continue;
                    }else if(ele.equals(ElementEnum.roadSign) && !TextTypeEnum.LableIconSymbolizer.equals(text.getTexttype())){
                        continue;
                    }
                    //text.getStyleTypeId() 此对象中的styleTypeId 为 point,line,roadSign中的 styleTypeId
                    StyleType styleType = styleTypeService.getStyleType(text.getStyleTypeId(),styleTypeList);
                    Element ruleDom = geneRuleTextDom(styleType, text);
                    if(!styleType.equals(tempStyle)){
                        if(textDom!=null){
                            //切换了不同Style时，完成上一个styleDefine
                            processTextRuleDom(firstRuleDom,"last");
                            textDom.add(firstRuleDom);
                            firstRuleDom = null;
                            textStyleDefine.add(textDom);
                        }
                        tempStyle = styleType;
                        //遇到新的文本样式时 ，添加新的 aliasTextDefine
                        Element dom = new DOMElement("AliasItem");
                        StyleType existsTextStyle = styleTypeService.getExistsTextStyle(styleType.getTextTypeId());
                        String aliasName;
                        if(existsTextStyle!=null){
                            if(!usedTextIds.contains(existsTextStyle.getId())){
                                aliasName = existsTextStyle.getName();
                                dom.addAttribute("AliasName", aliasName);
                                dom.addAttribute("StyleID",ByteUtil.parseString(existsTextStyle.getCode()));
                                usedTextIds.add(existsTextStyle.getId());
                            }else{
                                aliasName = tempStyle.getName()+"_"+existsTextStyle.getName();
                                dom.addAttribute("AliasName", aliasName);
                                StyleType textStyleType = styleTypeService.getOrInsertStyle(ElementEnum.text,aliasName);
                                dom.addAttribute("StyleID",textStyleType.getCode().toString());
                            }
                        }else{
                            aliasName = tempStyle.getName() + "_ctext";
                            dom.addAttribute("AliasName", aliasName);
                            StyleType textStyleType = styleTypeService.getOrInsertStyle(ElementEnum.text,aliasName);
                            dom.addAttribute("StyleID",textStyleType.getCode().toString());
                        }
                        tempStyle.setTextAliasName(aliasName);
                        notSortedList.add(dom);
                        //遇到新的文本样式时 ，创建新的 textStyleDefine
                        textDom = createStyleDom(ElementEnum.text,aliasName);
                    }

                    if(firstRuleDom ==null){
                        firstRuleDom = ruleDom;
                        processTextRuleDom(firstRuleDom,"first");
                    }
                    if(mergeRule("TextSymbolizer",firstRuleDom,ruleDom)){
                        //如果能成功合并两个rule,说明两个rule 一样
                        continue;
                    }else {
                        //如果不能成功合并,两个rule不一样，添加firstRuleDom，并将firstRuleDom 设置 为ruleDom。
                        textDom.add(firstRuleDom);
                        firstRuleDom = ruleDom;
                    }

                }
                if(textDom!=null){
                    //最后一个styleDefine
                    processTextRuleDom(firstRuleDom,"last");
                    textDom.add(firstRuleDom);
                    textStyleDefine.add(textDom);
                }
            }


            Element aliasDefine = aliasStyleDefine.element(ele.getTypeTag());
            for(StyleType styleType:styleTypeList){
                Element dom = new DOMElement("AliasItem");
                dom.addAttribute("AliasName",styleType.getName());
                dom.addAttribute("StyleID",ByteUtil.parseString(styleType.getCode()));
                aliasDefine.add(dom);
            }

            Element firstRuleDom = null;
            switch (ele){
                case point:
                    StyleType pointStyle = null;
                    Element pointDom = null;
                    for(RulePoint rule:points){
                        StyleType styleType = styleTypeService.getStyleType(rule.getStyleTypeId(),styleTypeList);
                        Element ruleDom = geneRulePointDom(styleType, rule,iconMap);

                        if(!styleType.equals(pointStyle)){
                            if(pointDom!=null){
                                //切换了不同Style时，完成上一个styleDefine
                                pointDom.add(firstRuleDom);
                                firstRuleDom = null;
                                pointStyleDefine.add(pointDom);
                            }
                            pointStyle = styleType;
                            //遇到新的文本样式时 ，创建新的 pointStyleDefine
                            pointDom = createStyleDom(ele, styleType.getName());
                        }

                        if(firstRuleDom ==null){
                            firstRuleDom = ruleDom;
                        }

                        if(mergeRule("PointSymbolizer",firstRuleDom,ruleDom)){
                            //如果能成功合并两个rule,说明两个rule 一样
                            continue;
                        }else {
                            //如果不能成功合并,两个rule不一样，添加firstRuleDom，并将firstRuleDom 设置 为ruleDom。
                            pointDom.add(firstRuleDom);
                            firstRuleDom = ruleDom;
                        }
                    }
                    if(pointDom!=null){
                        //最后一个styleDefine
                        pointDom.add(firstRuleDom);
                        pointStyleDefine.add(pointDom);
                    }
                    break;
                case line:
                    StyleType lineStyle = null;
                    Element lineDom = null;
                    for(RuleLine rule:lines){
                        StyleType styleType = styleTypeService.getStyleType(rule.getStyleTypeId(),styleTypeList);
                        Element ruleDom = geneRuleLineDom(styleType, rule,iconMap);
                        if(!styleType.equals(lineStyle)){
                            if(lineDom!=null){
                                lineDom.add(firstRuleDom);
                                firstRuleDom = null;
                                lineStyleDefine.add(lineDom);
                            }
                            lineStyle = styleType;
                            //遇到新的文本样式时 ，创建新的 lineStyleDefine
                            lineDom = createStyleDom(ele, styleType.getName());
                        }
                        if(firstRuleDom ==null){
                            firstRuleDom = ruleDom;
                        }

                        if(mergeRule("LineSymbolizer",firstRuleDom,ruleDom)){
                            //如果能成功合并两个rule,说明两个rule 一样
                            continue;
                        }else {
                            //如果不能成功合并,两个rule不一样，添加firstRuleDom，并将firstRuleDom 设置 为ruleDom。
                            lineDom.add(firstRuleDom);
                            firstRuleDom = ruleDom;
                        }
                    }
                    if(lineDom!=null){
                        //最后一个styleDefine
                        lineDom.add(firstRuleDom);
                        lineStyleDefine.add(lineDom);
                    }
                    break;
                case polygon:
                    StyleType polygonStyle = null;
                    Element polygonDom = null;
                    for(RulePolygon rule:polygons){
                        StyleType styleType = styleTypeService.getStyleType(rule.getStyleTypeId(),styleTypeList);
                        Element ruleDom = geneRulePolygonDom(styleType, rule,iconMap);
                        if(!styleType.equals(polygonStyle)){
                            if(polygonDom!=null){
                                polygonDom.add(firstRuleDom);
                                firstRuleDom = null;
                                polygonStyleDefine.add(polygonDom);
                            }
                            polygonStyle = styleType;
                            //遇到新的文本样式时 ，创建新的 polygonStyleDefine
                            polygonDom = createStyleDom(ele, styleType.getName());
                        }
                        if(firstRuleDom ==null){
                            firstRuleDom = ruleDom;
                        }

                        if(mergeRule("PolygonSymbolizer",firstRuleDom,ruleDom)){
                            //如果能成功合并两个rule,说明两个rule 一样
                            continue;
                        }else {
                            //如果不能成功合并,两个rule不一样，添加firstRuleDom，并将firstRuleDom 设置 为ruleDom。
                            polygonDom.add(firstRuleDom);
                            firstRuleDom = ruleDom;
                        }
                    }

                    if(polygonDom!=null){
                        //最后一个styleDefine
                        polygonDom.add(firstRuleDom);
                        polygonStyleDefine.add(polygonDom);
                    }
                    break;
                case building:
                    StyleType buildingStyle = null;
                    Element buildingDom = null;
                    for(RuleBuilding rule:buildings){
                        StyleType styleType = styleTypeService.getStyleType(rule.getStyleTypeId(),styleTypeList);
                        Element ruleDom = geneRuleBuildingDom(styleType, rule,iconMap);
                        if(!styleType.equals(buildingStyle)){
                            if(buildingDom!=null){
                                buildingDom.add(firstRuleDom);
                                firstRuleDom = null;
                                buildingStyleDefine.add(buildingDom);
                            }
                            buildingStyle = styleType;
                            //遇到新的文本样式时 ，创建新的 buildingStyleDefine
                            buildingDom = createStyleDom(ele, styleType.getName());
                        }
                        if(firstRuleDom ==null){
                            firstRuleDom = ruleDom;
                        }

                        if(mergeRule("BuildingSymbolizer",firstRuleDom,ruleDom)){
                            //如果能成功合并两个rule,说明两个rule 一样
                            continue;
                        }else {
                            //如果不能成功合并,两个rule不一样，添加firstRuleDom，并将firstRuleDom 设置 为ruleDom。
                            buildingDom.add(firstRuleDom);
                            firstRuleDom = ruleDom;
                        }
                    }

                    if(buildingDom!=null){
                        //最后一个styleDefine
                        buildingDom.add(firstRuleDom);
                        buildingStyleDefine.add(buildingDom);
                    }
                    break;
                case arrow:
                    StyleType arrowStyle = null;
                    Element arrowDom = null;
                    for(RuleArrow rule:arrows){
                        StyleType styleType = styleTypeService.getStyleType(rule.getStyleTypeId(),styleTypeList);
                        Element ruleDom = geneRuleArrowDom(styleType, rule,iconMap);
                        if(!styleType.equals(arrowStyle)){
                            if(arrowDom!=null){
                                arrowDom.add(firstRuleDom);
                                firstRuleDom = null;
                                arrowStyleDefine.add(arrowDom);
                            }
                            arrowStyle = styleType;
                            //遇到新的文本样式时 ，创建新的 arrowStyleDefine
                            arrowDom = createStyleDom(ele, styleType.getName());
                        }
                        if(firstRuleDom ==null){
                            firstRuleDom = ruleDom;
                        }

                        if(mergeRule("ArrowSymbolizer",firstRuleDom,ruleDom)){
                            //如果能成功合并两个rule,说明两个rule 一样
                            continue;
                        }else {
                            //如果不能成功合并,两个rule不一样，添加firstRuleDom，并将firstRuleDom 设置 为ruleDom。
                            arrowDom.add(firstRuleDom);
                            firstRuleDom = ruleDom;
                        }
                    }

                    if(arrowDom!=null){
                        //最后一个styleDefine
                        arrowDom.add(firstRuleDom);
                        arrowStyleDefine.add(arrowDom);
                    }
                    break;
                case roadSign:
                    StyleType roadSignStyle = null;
                    Element roadSignDom = null;
                    for(RuleRoadSign rule:roadSigns){
                        StyleType styleType = styleTypeService.getStyleType(rule.getStyleTypeId(),styleTypeList);
                        Element ruleDom = geneRuleRoadSignDom(styleType, rule,iconMap);
                        if(!styleType.equals(roadSignStyle)){
                            if(roadSignDom!=null){
                                roadSignDom.add(firstRuleDom);
                                firstRuleDom = null;
                                roadSignStyleDefine.add(roadSignDom);
                            }
                            roadSignStyle = styleType;
                            //遇到新的文本样式时 ，创建新的 roadSignStyleDefine
                            roadSignDom = createStyleDom(ele, styleType.getName());
                        }

                        if(firstRuleDom ==null){
                            firstRuleDom = ruleDom;
                        }

                        if(mergeRule("RoadSignSymbolizer",firstRuleDom,ruleDom)){
                            //如果能成功合并两个rule,说明两个rule 一样
                            continue;
                        }else {
                            //如果不能成功合并,两个rule不一样，添加firstRuleDom，并将firstRuleDom 设置 为ruleDom。
                            roadSignDom.add(firstRuleDom);
                            firstRuleDom = ruleDom;
                        }
                    }

                    if(roadSignDom!=null){
                        //最后一个styleDefine
                        roadSignDom.add(firstRuleDom);
                        roadSignStyleDefine.add(roadSignDom);
                    }
                    break;
            }


        }
        Collections.sort(notSortedList,new StyleDefineComparator());
        for(Element aliasItem:notSortedList){
            aliasTextDefine.add(aliasItem);
        }

        return doc;
    }




    private boolean mergeRule(String symbolizerName,Element firstRuleDom, Element ruleDom) {
        if(firstRuleDom.equals(ruleDom)){
            return true;
        }
        if(firstRuleDom.element(symbolizerName).asXML().equals(ruleDom.element(symbolizerName).asXML())){
            //两个样式一样，合并scale至 firstRuleDom
            String firstScale = firstRuleDom.element("Scale").getText();
            String secondScale = ruleDom.element("Scale").getText();
            String scale = firstScale.substring(0,firstScale.indexOf(","))+secondScale.substring(secondScale.indexOf(","),secondScale.length());
            firstRuleDom.element("Scale").setText(scale);
            return true;
        }else{
            return false;
        }
    }





    Element geneRulePointDom(StyleType styleType, RulePoint rule,Map<String,IconPojo> iconMap) {
     /* <Rule>
        <Scale>0,20</Scale>
        <PointSymbolizer poi-type="0" placement-type="point" icon-name="" text-name="" density="0" allow-overlap="0" tag-for-modify="789456"/>
      </Rule>*/
        Element ruleDom = new DOMElement("Rule");
        Element scaleDom = new DOMElement("Scale");
        scaleDom.setText(rule.getScale());
        Element symbolizer = new DOMElement("PointSymbolizer");
        symbolizer.addAttribute("poi-type",ByteUtil.parseString(rule.getPoiType()));
        symbolizer.addAttribute("placement-type","point");
        symbolizer.addAttribute("icon-name",getIconAliasName(rule.getIconName(),iconMap));
        symbolizer.addAttribute("text-name",rule.getDictFontName()==null?"": styleType.getTextAliasName());
        symbolizer.addAttribute("density",ByteUtil.parseString(rule.getPointDensity()));
        symbolizer.addAttribute("allow-overlap",ByteUtil.parseString(rule.getAllowOverlap()));
        symbolizer.addAttribute("tag-for-modify",styleType.getTagForModify());
        ruleDom.add(scaleDom);
        ruleDom.add(symbolizer);
        return ruleDom;
    }


    private Element geneRuleLineDom(StyleType styleType, RuleLine rule,Map<String,IconPojo> iconMap) {
        /*<Rule>
        <Scale>0,17</Scale>
        <LineSymbolizer stroke="#F2D18C" stroke-width="8" stroke-side="#afafa9" side-width="0" line-cap="round" line-join="round" line-level="2"
        stroke-texture="hd_white" side-texture="" side-wall-texture="" model-height="0" dash-line-name="" text-name="" type="line" tag-for-modify=""/>
      </Rule>*/
        Element ruleDom = new DOMElement("Rule");
        Element scaleDom = new DOMElement("Scale");
        scaleDom.setText(rule.getScale());
        Element symbolizer = new DOMElement("LineSymbolizer");
        symbolizer.addAttribute("stroke",rule.getDictStroke()==null?"":rule.getDictStroke().getRgbw());
        symbolizer.addAttribute("stroke-width",ByteUtil.parseString(rule.getStrokeWidth()));
        symbolizer.addAttribute("stroke-side",rule.getDictStrokeSide()==null?"":rule.getDictStrokeSide().getRgbw());
        symbolizer.addAttribute("side-width",ByteUtil.parseString(rule.getSideWidth()));
        symbolizer.addAttribute("line-cap",rule.getLineCap());
        symbolizer.addAttribute("line-join",rule.getLineJoin());
        symbolizer.addAttribute("line-level",ByteUtil.parseString(rule.getLineLevel()));
        symbolizer.addAttribute("stroke-texture",getIconAliasName(rule.getStrokeTexture(),iconMap));
        symbolizer.addAttribute("side-texture",getIconAliasName(rule.getSideTexture(),iconMap));
        symbolizer.addAttribute("side-wall-texture",getIconAliasName(rule.getSideWallTexture(),iconMap));
        symbolizer.addAttribute("model-height",ByteUtil.parseString(rule.getModelHeight()));
        symbolizer.addAttribute("dash-line-name",rule.getDictDashLineName()==null?"":rule.getDictDashLineName().getName());
        symbolizer.addAttribute("text-name",rule.getDictFontName()==null?"":styleType.getTextAliasName());
        symbolizer.addAttribute("type","line");
        symbolizer.addAttribute("tag-for-modify",styleType.getTagForModify());

        ruleDom.add(scaleDom);
        ruleDom.add(symbolizer);
        return ruleDom;
    }
    private Element geneRulePolygonDom(StyleType styleType, RulePolygon rule,Map<String,IconPojo> iconMap) {

        /*          <Rule>
        <Scale>0,20</Scale>
        <PolygonSymbolizer fill="#ffffff00" border-color="#ffffff00" border-width="0" region-texture="" border-texture="" region-type="null" tag-for-modify=""/>
      </Rule>*/
        Element ruleDom = new DOMElement("Rule");
        Element scaleDom = new DOMElement("Scale");
        scaleDom.setText(rule.getScale());
        Element symbolizer = new DOMElement("PolygonSymbolizer");
        symbolizer.addAttribute("fill",rule.getDictFill()==null?"":rule.getDictFill().getRgbw());
        symbolizer.addAttribute("border-color",rule.getDictBorderColor()==null?"":rule.getDictBorderColor().getRgbw());
        symbolizer.addAttribute("border-width",ByteUtil.parseString(rule.getBorderWidth()));
        symbolizer.addAttribute("region-texture",getIconAliasName(rule.getRegionTexture(),iconMap));
        symbolizer.addAttribute("border-texture",getIconAliasName(rule.getBorderTexture(),iconMap));
        symbolizer.addAttribute("region-type",rule.getRegionType());
        symbolizer.addAttribute("tag-for-modify",styleType.getTagForModify());
        ruleDom.add(scaleDom);
        ruleDom.add(symbolizer);
        return ruleDom;
    }
    private Element geneRuleBuildingDom(StyleType styleType, RuleBuilding rule,Map<String,IconPojo> iconMap) {
       /* <Rule>
        <Scale>0,20</Scale>
        <BuildingSymbolizer roof-color="#f3f3f2" root-color="#c1c1c1" wall-color="#ffffff" window-color="#ffffff" roof-line-color="#eaeaea" wall-line-color="#ffffff" diffuse="0.2"
         light-source="face_in" roof-texture="" wall-texture="window" window-repeat="1" roof-line-color-2d="#c7c7ab80" roof-color-2d="#fffff7cc" tag-for-modify=""/>
      </Rule>*/
        Element ruleDom = new DOMElement("Rule");
        Element scaleDom = new DOMElement("Scale");
        scaleDom.setText(rule.getScale());
        Element symbolizer = new DOMElement("BuildingSymbolizer");
        symbolizer.addAttribute("roof-color",rule.getDictRoofColor()==null?"":rule.getDictRoofColor().getRgbw());
        symbolizer.addAttribute("root-color",rule.getDictRootColor()==null?"":rule.getDictRootColor().getRgbw());
        symbolizer.addAttribute("wall-color",rule.getDictWallColor()==null?"":rule.getDictWallColor().getRgbw());
        symbolizer.addAttribute("window-color",rule.getDictWindowColor()==null?"":rule.getDictWindowColor().getRgbw());
        symbolizer.addAttribute("roof-line-color",rule.getDictRoofLineColor()==null?"":rule.getDictRoofLineColor().getRgbw());
        symbolizer.addAttribute("wall-line-color",rule.getDictWallLineColor()==null?"":rule.getDictWallLineColor().getRgbw());
        symbolizer.addAttribute("diffuse",ByteUtil.parseString(rule.getDiffuse()));

        symbolizer.addAttribute("light-source",rule.getLightSource());
        symbolizer.addAttribute("roof-texture",getIconAliasName(rule.getRoofTexture(),iconMap));
        symbolizer.addAttribute("wall-texture",getIconAliasName(rule.getWallTexture(),iconMap));
        symbolizer.addAttribute("window-repeat",ByteUtil.parseString(rule.getWindowRepeat()));
        symbolizer.addAttribute("roof-line-color-2d",rule.getDictRoofLineColor2d()==null?"":rule.getDictRoofLineColor2d().getRgbw());
        symbolizer.addAttribute("roof-color-2d",rule.getDictRoofColor2d()==null?"":rule.getDictRoofColor2d().getRgbw());
        symbolizer.addAttribute("tag-for-modify",styleType.getTagForModify());

        ruleDom.add(scaleDom);
        ruleDom.add(symbolizer);
        return ruleDom;
    }
    private Element geneRuleArrowDom(StyleType styleType, RuleArrow rule,Map<String,IconPojo> iconMap) {
     /* <Rule>
        <Scale>0,20</Scale>
        <ArrowSymbolizer TailAndHeadDist="80" LabelDistance="400" color="#afafaf" width="1.5" length="10" texture="icon_arrow" tag-for-modify=""/>
      </Rule>*/
        Element ruleDom = new DOMElement("Rule");
        Element scaleDom = new DOMElement("Scale");
        scaleDom.setText(rule.getScale());
        Element symbolizer = new DOMElement("ArrowSymbolizer");
        symbolizer.addAttribute("TailAndHeadDist",ByteUtil.parseString(rule.getTailAndHeadDist()));
        symbolizer.addAttribute("LabelDistance",ByteUtil.parseString(rule.getLabelDistance()));
        symbolizer.addAttribute("color",rule.getDictColor()==null?"":rule.getDictColor().getRgbw());
        symbolizer.addAttribute("width",ByteUtil.parseString(rule.getWidth()));
        symbolizer.addAttribute("length",ByteUtil.parseString(rule.getLength()));
        symbolizer.addAttribute("texture",getIconAliasName(rule.getTexture(),iconMap));
        symbolizer.addAttribute("tag-for-modify",styleType.getTagForModify());
        ruleDom.add(scaleDom);
        ruleDom.add(symbolizer);
        return ruleDom;
    }
    private Element geneRuleRoadSignDom(StyleType styleType, RuleRoadSign rule,Map<String,IconPojo> iconMap) {
        /*<Rule>
        <Scale>0,20</Scale>
        <RoadSignSymbolizer iconname="icon_NationalHighway" textname="roadgg_lable_t" tag-for-modify="" stretching-len=""/>
      </Rule>*/
        Element ruleDom = new DOMElement("Rule");
        Element scaleDom = new DOMElement("Scale");
        scaleDom.setText(rule.getScale());
        Element symbolizer = new DOMElement("RoadSignSymbolizer");
        symbolizer.addAttribute("iconname",getIconAliasName(rule.getIconname(),iconMap));
        symbolizer.addAttribute("textname",rule.getDictFontName()==null?"":styleType.getTextAliasName());
        symbolizer.addAttribute("tag-for-modify", styleType.getTagForModify());
        symbolizer.addAttribute("stretching-len",ByteUtil.parseString(rule.getStretchingLen()));
        ruleDom.add(scaleDom);
        ruleDom.add(symbolizer);
        return ruleDom;
    }

    /**
     * 填充点线划样式信息至 xml中
     * @param aliasStyleDefine
     * @param commonStyleDefine
     * @param dashLines
     */
    private void fillDashLineStyleDefine(Element aliasStyleDefine,Element commonStyleDefine, List<DictDashLine> dashLines) {


        Element aliasDefine = aliasStyleDefine.element("AliasDashLineStyleDefine");
        Element styleDefine = commonStyleDefine.element("DashLineStyleDefine");

        for(DictDashLine dashLine:dashLines){
            Element aliasItem = geneDashLineAliasItem(dashLine);
            Element styleItem = geneDashLineItem(dashLine);
            aliasDefine.add(aliasItem);
            styleDefine.add(styleItem);
        }
    }

    /**
     * 获取某版本样式中所有使用到的图标
     * @param instance
     * @return
     */
    private LinkedHashMap<String,IconPojo> getAllIcon(Instance instance){
        Integer instanceId = instance.getId();
        LinkedHashMap<String,IconPojo> map = new LinkedHashMap<>();
        ArrayList params = new ArrayList();
        String sql = "select x.name," +
                "i.id as iconId, i.typeId as folderId,i.path,i.width,i.height," +
                "s.aliasName,s.styleID," +
                "d.iconType,d.scaleId," +
                "(select t.text from icon_type t where t.id = ?) as folder from (" +
                " select iconName name from rule_point where instanceId = ? and iconName is not null union"+
                " select strokeTexture name from rule_line where instanceId = ? and strokeTexture is not null union"+
                " select sideWallTexture name from rule_line where instanceId = ? and sideWallTexture is not null union"+
                " select sideTexture name from rule_line where instanceId = ? and sideTexture is not null union"+
                " select regionTexture name from rule_polygon where instanceId = ? and regionTexture is not null union"+
                " select borderTexture name from rule_polygon where instanceId = ? and borderTexture is not null union"+
                " select roofTexture name from rule_building where instanceId = ? and roofTexture is not null union"+
                " select wallTexture name from rule_building where instanceId = ? and wallTexture is not null union"+
                " select texture name from rule_arrow where instanceId = ? and texture is not null union"+
                " select iconname name from rule_roadSign where instanceId = ? and iconname is not null"+
                ") x " +
                " left join instance_icon s on s.fileName = x.name and s.instanceId = ? " +
                " left join icon i on x.name = i.name and i.typeId = ? " +
                " left join icon_distri d on d.name = x.name " +
                " order by d.iconType desc,s.styleID asc";

        params.add(instance.getFolderId());
        for(int i =0;i<11;i++){
            params.add(instanceId);
        }
        params.add(instance.getFolderId());
        List<IconPojo> icons = sql(sql).list(IconPojo.class,params.toArray());
        Long maxIconCode = sql("select max(cast(substr(aliasName,6) as SIGNED)) from instance_icon where instanceId = ? and aliasName like 'icon_%'").one(Long.class,instanceId);
        Integer maxIconStyleId = sql("select max(styleID) from instance_icon where instanceId = ?").one(Integer.class,instanceId);

        int beginIndex = 0;
        if(maxIconCode != null || maxIconStyleId!=null){
            maxIconCode = maxIconCode == null?0l:maxIconCode;
            maxIconStyleId = maxIconStyleId == null?0:maxIconStyleId;
            beginIndex = maxIconStyleId>maxIconCode?(maxIconStyleId+1):(maxIconCode.intValue()+1);
        }

        HashMap<String,Icon> allIcons = iconService.getAllIcons(instance.getFolderId());
        for(int i =0;i<icons.size();i++){
            IconPojo icon = icons.get(i);
            if(StringUtils.isEmpty(icon.getName())){
                continue;
            }
            if(icon.getStyleID()==null){
                icon.setAliasName("icon_"+(i+beginIndex));
                icon.setStyleID(i+1+beginIndex);
            }
            icon.setName(icon.getName().replaceAll("@\\dx.","."));
            if(icon.getIconId() == null){
               Icon otherIcon = allIcons.get(icon.getName());
               if(otherIcon != null){
                   icon.setIconId(otherIcon.getId());
                   icon.setFolderId(otherIcon.getTypeId());
                   icon.setPath(otherIcon.getPath());
                   icon.setWidth(otherIcon.getWidth());
                   icon.setHeight(otherIcon.getHeight());
               }
            }
            map.put(icon.getName(),icon);
        }
        //导出图片时用得着，但是现在是导出导出图片夹里所有图片，暂时用不着了。
        Map<Integer,IconPojo> iconPojoMap = iconPojoMapThreadLocal.get();
        for(IconPojo icon:icons){
            if(iconPojoMap !=null && icon.getIconId()!=null){
                iconPojoMap.put(icon.getIconId(),icon);
            }
        }
        return map;
    }

    Element createStyleDom(ElementEnum ele, String name) {
        Element pointDom = new DOMElement("Style");
        pointDom.addAttribute("name",name);
        pointDom.addAttribute("type",ele.getType().toString());
        return pointDom;
    }

    Element geneRuleTextDom(StyleType textStyle, RuleText text) {
      /*  <Rule>
        <Scale>0,20</Scale>
        <TextSymbolizer font-name="FONT_STYLE_CHN" font-size="15" font-color="##005E8E" font-weight="normal" font-style="halo" halosize="1" bgsize="0" halocolor="#ffffffb3" density="24" fillarc="1.5" texttype="PointTextSymbolizer" tag-for-modify=""/>
      </Rule>*/
        Element ruleDom = new DOMElement("Rule");
        Element scaleDom = new DOMElement("Scale");
        scaleDom.setText(text.getScale());
        Element textSymbolizer = new DOMElement("TextSymbolizer");
        textSymbolizer.addAttribute("font-name",text.getDictFontName()==null?"":text.getDictFontName().getVal());
        textSymbolizer.addAttribute("font-size", text.getDictFontSize()==null?"":text.getDictFontSize().getVal().toString());
        textSymbolizer.addAttribute("font-color",text.getDictFontColor()==null?"":text.getDictFontColor().getRgbw());
        textSymbolizer.addAttribute("font-weight",text.getFontWeight());
        textSymbolizer.addAttribute("font-style",text.getFontStyle());
        textSymbolizer.addAttribute("halosize",ByteUtil.parseString(text.getHalosize()));
        textSymbolizer.addAttribute("bgsize",ByteUtil.parseString(text.getBgsize()));
        textSymbolizer.addAttribute("halocolor",text.getDictHalocolor()==null?"":text.getDictHalocolor().getRgbw());
        textSymbolizer.addAttribute("density",ByteUtil.parseString(text.getDensity()));
        textSymbolizer.addAttribute("fillarc",ByteUtil.parseString(text.getFillarc()));
        textSymbolizer.addAttribute("texttype",text.getTexttype().name());
        textSymbolizer.addAttribute("tag-for-modify",textStyle.getTextTag());
        ruleDom.add(scaleDom);
        ruleDom.add(textSymbolizer);
        return ruleDom;
    }

    private void processTextRuleDom(Element firstRuleDom, String firstOrLast) {
        Element scaleDom = firstRuleDom.element("Scale");
        String scaleStr = scaleDom.getText();
        String[] strs = scaleStr.split(",");
        String from = strs[0];
        String to = strs[1];
        if("first".equals(firstOrLast) && !"0".equals(from)){
            from = "0";
        }else if("last".equals(firstOrLast) && !"20".equals(to)){
            to = "20";
        }
        scaleDom.setText(from+","+to);
    }


    private Element geneIconAliasItem(IconPojo icon) {
        Element ele = new DOMElement("AliasItem");
        ele.addAttribute("AliasName",icon.getAliasName());
        ele.addAttribute("StyleID",icon.getStyleID().toString());
        return ele;
    }

    /**
     * 向xml的aliasStyleDefine 与 commonStyleDefine 中添加图标定义
     * @param aliasStyleDefine
     * @param commonStyleDefine
     * @param iconMap
     */
    private void fillIconStyleDefine(Element aliasStyleDefine,Element commonStyleDefine, Map<String, IconPojo> iconMap) {
        Element aliasDefine = aliasStyleDefine.element("AliasIconStyleDefine");
        Element styleDefine = commonStyleDefine.element("IconStyleDefine");
        List<Element> notSortedList = new ArrayList();
        for(IconPojo icon:iconMap.values()){
            Element aliasItem = geneIconAliasItem(icon);
            Element styleItem = geneIconItem(icon);

            notSortedList.add(aliasItem);
            styleDefine.add(styleItem);
        }
        notSortedList.sort((a,b)-> {
            Integer StyleID1 = Integer.valueOf(a.attributeValue("StyleID"));
            Integer StyleID2 = Integer.valueOf(b.attributeValue("StyleID"));
            return StyleID1.compareTo(StyleID2);
        });
        for(Element aliasItem:notSortedList){
            aliasDefine.add(aliasItem);
        }
    }

    private Element geneIconItem(IconPojo icon) {
        /* <IconItem icon-name="icon_161" icon-type="sprite_sheet" icon-filename="poi_icon/161.png">
                <IconLayer icon-file="poi_icon.png" offset-x="224" offset-y="112" width="16" height="16" scaleid="161" />
            </IconItem>
           <IconItem icon-name="logo_zh_1_icon" icon-type="image" icon-filename="mapcfg_logo_zh_1_icon/mapcfg_logo_zh_1_icon.png">
                <IconLayer icon-file="mapcfg_logo_zh_1_icon.png" offset-x="0" offset-y="0" width="40" height="40" scaleid="230" />
            </IconItem>
            */

        Element ele = new DOMElement("IconItem");
        ele.addAttribute("icon-name",icon.getAliasName());



        Element iconLayer = new DOMElement("IconLayer");
        if(new Integer(2).equals(icon.getIconType())){
            //sprite_sheet
            iconLayer.addAttribute("icon-file",icon.getFolder()+".png");
        }else{
            iconLayer.addAttribute("icon-file",icon.getName());
        }

        iconLayer.addAttribute("offset-x","0");
        iconLayer.addAttribute("offset-y","0");
        iconLayer.addAttribute("width",ByteUtil.parseString(icon.getWidth()));
        iconLayer.addAttribute("height",ByteUtil.parseString(icon.getHeight()));

        if(new Integer(2).equals(icon.getIconType())){
            //sprite_sheet
            ele.addAttribute("icon-type", IconTypeEnum.sprite_sheet.name());
            iconLayer.addAttribute("scaleid",(icon.getStyleID()-1)+"");
        }else{
            ele.addAttribute("icon-type",IconTypeEnum.image.name());
            iconLayer.addAttribute("scaleid",ByteUtil.parseString(icon.getScaleId()));
        }

        ele.addAttribute("icon-filename",icon.getFolder()+"/"+icon.getName());

        // <IconLayer ="mapcfg_545.png" offset-x="0" offset-y="0" width="27" height="15" scaleid=""/>
        ele.add(iconLayer);
        return ele;
    }


    private String getIconAliasName(String iconName, Map<String, IconPojo> iconMap) {
        if(StringUtils.isEmpty(iconName)){
            return "";
        }
        IconPojo icon = iconMap.get(iconName.replaceAll("@\\dx.","."));
        if(icon!=null){
            return icon.getAliasName();
        }
        return "";
    }

    private Element geneDashLineAliasItem(DictDashLine dashLine) {
        Element ele = new DOMElement("AliasItem");
        ele.addAttribute("AliasName",dashLine.getName());
        StyleType styleType = styleTypeService.getOrInsertStyle(ElementEnum.dashLine,dashLine.getName());
        ele.addAttribute("StyleID",styleType.getCode()+"");
        return ele;
    }

    private Element geneDashLineItem(DictDashLine dashLine) {
        //<DashLineItem dash-line-name="dash11" from="0" to="20" side-dashline-array="" stroke-dashline-array="1,1" x-roate="0" x-antialising="on"/>
        Element ele = new DOMElement("DashLineItem");
        ele.addAttribute("dash-line-name",dashLine.getName());
        ele.addAttribute("from", ByteUtil.parseString(dashLine.getBegin()));
        ele.addAttribute("to",ByteUtil.parseString(dashLine.getEnd()));
        ele.addAttribute("side-dashline-array",dashLine.getSideDashlineArray());
        ele.addAttribute("stroke-dashline-array",dashLine.getStrokeDashlineArray());
        ele.addAttribute("x-roate",ByteUtil.parseString(dashLine.getxRoate()));
        ele.addAttribute("x-antialising",dashLine.getxAntialising());
        return ele;
    }

    public void releaseStyle(Release release) throws DocumentException, IOException {
        //保存记录
        if(release.getId() == null){
            insert(release);
        }
        File absFolder = new File(Constants.webRoot.getAbsolutePath(),Constants.RELEASE_PATH);
        if(!absFolder.exists()) absFolder.mkdirs();
        String zipFileName = "release_"+release.getId()+".zip";
        release.setZipPath(Constants.RELEASE_PATH+"/"+zipFileName);

        File zipFile = new File(absFolder,zipFileName);
        FileOutputStream outputStream = new FileOutputStream(zipFile);
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);

        //生成所有的xml 并zip

        ReleaseService.iconPojoMapThreadLocal.set(new HashMap<>());
        String instanceIds = release.getInstanceIds();

        List<Integer> folderIds = new ArrayList<>();
        int count;
        byte[] buf = new byte[1024];
        for(String instanceId :instanceIds.split(",")){
            Instance instance = instanceService.getInstance(Integer.parseInt(instanceId));
            folderIds.add(instance.getFolderId());
            Document doc = geneXml(instance);
            StringWriter stringWriter = XmlUtil.formatDom(doc);
            BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(stringWriter.toString().getBytes()));
            zipOutputStream.putNextEntry(new ZipEntry(instance.getXmlName()));
            //将源文件写入到zip文件中
            while((count=bis.read(buf))!=-1)
            {
                zipOutputStream.write(buf,0,count);
            }
            bis.close();
        }
        List<IconPojo> icons = sql("select i.path,i.name,(select t.text from icon_type t where t.id = i.typeId) as folder from icon i  where i.typeId in("+genePlaceHolders(folderIds.size())+")").list(IconPojo.class,folderIds.toArray());
        for(IconPojo icon:icons){
            File iconFile = new File(Constants.webRoot+icon.getPath());
            if(iconFile.exists()){
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(iconFile));
                zipOutputStream.putNextEntry(new ZipEntry(icon.getFolder()+"/"+icon.getName()));
                while((count=bis.read(buf))!=-1)
                {
                    zipOutputStream.write(buf,0,count);
                }
                bis.close();
            }
        }
        //输出附件
        Integer attachmentFolderId = release.getAttachmentFolderId();
        if(attachmentFolderId!=null){
            List<Attachment> items = sql("select i.path,i.name from attachment i  where i.folderId = ?").list(Attachment.class,attachmentFolderId);
            for(Attachment item:items){
                File file = new File(Constants.webRoot+item.getPath());
                if(file.exists()){
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                    zipOutputStream.putNextEntry(new ZipEntry(item.getName()));
                    while((count=bis.read(buf))!=-1)
                    {
                        zipOutputStream.write(buf,0,count);
                    }
                    bis.close();
                }
            }
        }

       /* Map<Integer,IconPojo> iconPojoMap = ReleaseService.iconPojoMapThreadLocal.get();
        for(IconPojo icon:iconPojoMap.values()){
            File iconFile = new File(Constants.webRoot+icon.getPath());
            if(iconFile.exists()){
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(iconFile));
                zipOutputStream.putNextEntry(new ZipEntry(icon.getFolder()+"/"+icon.getName()));
                while((count=bis.read(buf))!=-1)
                {
                    zipOutputStream.write(buf,0,count);
                }
                bis.close();
            }
        }*/
        zipOutputStream.flush();
        zipOutputStream.close();
        //记录所有的图片  并zip

        //发布测试环境
        update(release);
    }

    public void sendToRemote(Release release) throws Exception{
        File file = new File(Constants.webRoot.getAbsolutePath(),release.getZipPath());
        String respFileName = null;
        try {
            if(!file.exists()){
                releaseStyle(release);
            }
            File respFolder = new File(Constants.webRoot.getAbsolutePath(),Constants.MAPCONFIG_PATH);
            if(!respFolder.exists()) respFolder.mkdirs();
            respFileName = "resp_"+release.getId()+".zip";
            File respFile = new File(respFolder,respFileName);
            HttpRequestUtil.uploadFile(releaseUrl+"?hd="+release.getHd(),file,respFile);
            release.setRespPath(Constants.MAPCONFIG_PATH+"/"+respFileName);
            release.setComment("发布成功！");
        } catch (Exception e) {
            release.setComment(e.getMessage());
            throw e;
        }finally {
            release.setModifier(SessionUtil.getCurUserId());
            release.setModifyTime(new Date());
            update(release);
        }
    }


    public void zip(String id) throws IOException, DocumentException {
       Release release = selectById(Release.class,id);
        release.setModifier(SessionUtil.getCurUserId());
        release.setModifyTime(new Date());
        releaseStyle(release);
    }


}
